﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;
using System.IO.Pipes;
using PeoneFS;
using ServiceTools;
using System.ServiceProcess;
using System.Reflection;
using Dokan;

namespace RunElevated
{
    class RunElevated
    {
        static FileSystemService fileSystemService = new FileSystemService();
        static void InstallService()
        {
            fileSystemService.InstallAndStart();
        }

        static void UninstallService()
        {
            fileSystemService.UninstallService();
        }

        static void RestartService()
        {
            fileSystemService.StopService();
            fileSystemService.StartService();
        }

        static void RunElevatedMethod(string argument)
        {
            if (isProcessElevated)
            {
                using (NamedPipeClientStream pipeClient =
                    new NamedPipeClientStream(".", "testpipe", PipeDirection.Out))
                {
                    pipeClient.Connect();

                    using (StreamWriter sw = new StreamWriter(pipeClient))
                    {
                        Console.SetOut(sw);
                        sw.AutoFlush = true;
                        Console.WriteLine("running elevated: {0}", argument);
                        if (argument == "install")
                        {
                            InstallService();
                        }

                        if (argument == "uninstall")
                        {
                            UninstallService();
                        }

                        if (argument == "restart")
                        {
                            RestartService();
                        }
                    }
                }

                return;
            }

            bool spawnedRunning = true;
            ManualResetEventSlim signal = new ManualResetEventSlim();
            Thread t = new Thread((o) =>
            {
                using (NamedPipeServerStream pipeServer =
                    new NamedPipeServerStream("testpipe", PipeDirection.In))
                {
                    signal.Set();
                    pipeServer.WaitForConnection();
                    try
                    {
                        // Read user input and send that to the client process.
                        using (StreamReader sr = new StreamReader(pipeServer))
                        {
                            string line = sr.ReadLine();
                            while ((line != null) && (spawnedRunning))
                            {
                                Console.WriteLine(line);
                                line = sr.ReadLine();
                            }
                        }
                    }
                    // Catch the IOException that is raised if the pipe is 
                    // broken or disconnected.
                    catch (IOException)
                    {
                    }
                }
            });

            t.Start();
            signal.Wait();
            ProcessStartInfo pi = new ProcessStartInfo(System.Reflection.Assembly.GetExecutingAssembly().Location, argument);
            //pi.RedirectStandardOutput = true;
            pi.Verb = "runas";
            pi.WindowStyle = ProcessWindowStyle.Hidden;
            Process.Start(pi).WaitForExit();
            spawnedRunning = false;
        }

        static void Usage()
        {
            try
            {
                var assembly = Assembly.GetExecutingAssembly();
                var textStreamReader = new StreamReader(assembly.GetManifestResourceStream("PeoneFS.usage.txt"));
                Console.WriteLine(String.Format(textStreamReader.ReadToEnd(), assembly.GetName().Version.ToString()));
            }
            catch
            {
                Console.WriteLine("u-oh!");
            }
        }
        static bool isProcessElevated = Process.GetCurrentProcess().IsProcessElevated();

        static void Main(string[] args)
        {
            bool isSpawned = ParentProcessHelper.GetParentProcess().ProcessName == Process.GetCurrentProcess().ProcessName;
            var FileSysService = new FileSystemService();
            if (args.Length == 1)
            {
                switch (args[0].ToLowerInvariant())
                {
                    case "install":
                        if (isSpawned || !isProcessElevated)
                        {
                            RunElevatedMethod("install");
                        }
                        else
                        {
                            InstallService();
                        }
                        return;

                    case "restart":
                        if (isSpawned || !isProcessElevated)
                        {
                            RunElevatedMethod("restart");
                        }
                        else
                        {
                            RestartService();
                        }
                        return;

                    case "uninstall":
                        if (isSpawned || !isProcessElevated)
                        {
                            RunElevatedMethod("uninstall");
                        }
                        else
                        {
                            UninstallService();
                        }
                        return;

                    case "test":
                        Thread t = FileSystemService.LaunchPeoneFS();
                        Console.WriteLine("PeoneFS is running. Press Control+C to stop the process");
                        Console.CancelKeyPress += (o, argms) =>
                            {
                                t.Abort();
                                DokanNet.DokanUnmount(Configuration.DriveLetter);
                            };
                        while (true)
                            Thread.Sleep(Int32.MaxValue);

                    case "status":
                        Console.WriteLine("PeoneFS is {0}", fileSystemService.Status);
                        return;

                    default:
                        Usage();
                        return;
                }
            }

            if (Environment.UserInteractive)
            {
                Usage();
                return;
            }
            var ServicesToRun = new ServiceBase[] { fileSystemService };
            ServiceBase.Run(ServicesToRun);
        }
    }
}
